﻿#region Using References

using System.Linq;
using Beaker.OpenCube.IO;
using Beaker.OpenCube.Specs.Builders;
using Beaker.Services.FileSystem;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

#endregion

namespace Beaker.OpenCube.Specs.IO
{
	[TestClass]
	public class FallbackFileSytemSpecs
	{
		[TestMethod]
		public void WhenFileInFirstReturnFirst()
		{
			// arrange
			IFileSystemService mainFolder =
				new FileSystemServiceBuilder()
					.WithFile( "Foo", new byte[] { 1 } )
					.Build();
			IFileSystemService fallbackFolder =
				new FileSystemServiceBuilder()
					.WithFile( "Foo", new byte[] { 2 } )
					.Build();

			IFileSystemService folder = mainFolder.Fallback( fallbackFolder );

			// act
			IFile file = folder.GetFile( "Foo" );

			// assert
			file.OpenRead().ReadByte().Should().Be( 1 );
		}

		[TestMethod]
		public void WhenFileNotInFirstReturnSecond()
		{
			// arrange
			IFileSystemService mainFolder =
				new FileSystemServiceBuilder()
					.WithFile( "Bar", new byte[] { 1 } )
					.Build();
			IFileSystemService fallbackFolder =
				new FileSystemServiceBuilder()
					.WithFile( "Foo", new byte[] { 2 } )
					.Build();

			IFileSystemService folder = mainFolder.Fallback( fallbackFolder );

			// act
			IFile file = folder.GetFile( "Foo" );

			// assert
			file.OpenRead().ReadByte().Should().Be( 2 );
		}


		[TestMethod]
		public void RecursiveWalkOverMultipleFilesReturnsTotalOfFirsts()
		{
			// arrange
			IFileSystemService mainFolder =
				new FileSystemServiceBuilder()
					.WithFile( "Shared/Folder1/Foo", new byte[] { 1 } )
					.WithFile( "Shared/Folder3/Foo", new byte[] { 4 } )
					.Build();
			IFileSystemService fallbackFolder =
				new FileSystemServiceBuilder()
					.WithFile( "Shared/Folder1/Foo", new byte[] { 2 } )
					.WithFile( "Shared/Folder2/Foo", new byte[] { 3 } )
					.Build();

			IFileSystemService folder = mainFolder.Fallback( fallbackFolder );

			// act
			IFolder sharedFolder = folder.GetFolder( "Shared" );

			// assert
			IFile[] files = sharedFolder.GetAllFilesRecursive().ToArray();
			files.Length
				.Should().Be( 3 );
			files.Select( f => f.OpenRead().ReadByte() )
				.Should().BeEquivalentTo( new[] { 1, 3, 4 } );
		}

		[TestMethod]
		public void WhenUsingActualParentFolderOtherFileIsTakenFromSameFolderAsFile()
		{
			// arrange
			IFileSystemService mainFolder =
				new FileSystemServiceBuilder()
					.WithFile( "Shared/Foo", new byte[] { 1 } )
					.Build();
			IFileSystemService fallbackFolder =
				new FileSystemServiceBuilder()
					.WithFile( "Shared/Foo", new byte[] { 3 } )
					.WithFile( "Shared/Bar", new byte[] { 4 } )
					.Build();

			IFileSystemService folder = mainFolder.Fallback( fallbackFolder );

			// act
			IFile file = folder.GetFile( "Shared", "Foo" ); // find in main
			IFolder actualFolder = file.GetActualParentFolder(); // get the actual folder
			IFile barFile = actualFolder.GetFile( "Bar" ); // should not return the fallback

			// assert
			barFile.Should().BeNull();
		}

		[TestMethod]
		public void WhenUsingActualParentFolderOtherFileIsTakenFromSameFolderAsFileEvenWhenOrignalIsFallback()
		{
			// arrange
			IFileSystemService mainFolder =
				new FileSystemServiceBuilder()
					.WithFile( "Shared/Bar", new byte[] { 1 } )
					.Build();
			IFileSystemService fallbackFolder =
				new FileSystemServiceBuilder()
					.WithFile( "Shared/Foo", new byte[] { 3 } )
					.WithFile( "Shared/Bar", new byte[] { 4 } )
					.Build();

			IFileSystemService folder = mainFolder.Fallback( fallbackFolder );

			// act
			IFile file = folder.GetFile( "Shared", "Foo" ); // find in fallback
			IFolder actualFolder = file.GetActualParentFolder(); // get the actual folder
			IFile barFile = actualFolder.GetFile( "Bar" ); // should return the fallback, even though there is a main

			// assert
			barFile.Should().NotBeNull();
			barFile.OpenRead().ReadByte().Should().Be( 4 );
		}
	}
}